/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.maven.ide.eclipse.sysdeotomcat;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.List;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.model.Plugin;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.maven.ide.eclipse.MavenPlugin;
import org.maven.ide.eclipse.embedder.IMaven;
import org.maven.ide.eclipse.project.IMavenProjectFacade;
import org.maven.ide.eclipse.project.MavenProjectManager;
import org.maven.ide.eclipse.project.configurator.AbstractProjectConfigurator;
import org.maven.ide.eclipse.project.configurator.ProjectConfigurationRequest;

import com.sysdeo.eclipse.tomcat.FileUtil;
import com.sysdeo.eclipse.tomcat.TomcatLauncherPlugin;
import com.sysdeo.eclipse.tomcat.TomcatProject;
import com.sysdeo.eclipse.tomcat.WebClassPathEntries;
import com.sysdeo.eclipse.tomcat.editors.ProjectListElement;

/**
 * @author ndeloof
 */
public class TomcatProjectConfigurator
    extends AbstractProjectConfigurator
{
    /** The tomcat context definition used for local testing */
    private static final String TOMCAT_CONTEXT = "src/test/tomcat/context.xml";

    public void configure( ProjectConfigurationRequest request, IProgressMonitor monitor )
        throws CoreException
    {
        MavenProject mavenProject = request.getMavenProject();
        if ( !mavenProject.getPackaging().equals( "war" ) )
        {
            return;
        }
        console.logMessage( "Configure Sysdeo Tomcat for war project " + mavenProject.getName() );
        IProject project = request.getProject();
        addNature( project, TomcatLauncherPlugin.NATURE_ID, monitor );

        Plugin warPlugin = mavenProject.getPlugin( "org.apache.maven.plugins:maven-war-plugin" );
        File basedir = mavenProject.getBasedir();

        TomcatProject tomcatProject = TomcatProject.create( project );
        if ( tomcatProject == null )
        {
            console.logError( "Failed to create TomcatProject from a maven WAR project." );
            return;
        }

        String rootDir = extractMavenConfiguration( warPlugin, "warSourceDirectory", "src/main/webapp" );
        tomcatProject.setRootDir( rootDir );

        String webPath = extractMavenConfiguration( warPlugin, "warName", mavenProject.getBuild().getFinalName() );
        console.logMessage( "Web application context path set to : " + webPath );
        tomcatProject.setWebPath( '/' + webPath );

        tomcatProject.setReloadable( true );
        tomcatProject.setRedirectLogger( true );
        tomcatProject.setUpdateXml( true );

        WebClassPathEntries entries = new WebClassPathEntries();
        String out = new File( mavenProject.getBuild().getOutputDirectory() ).getAbsolutePath();
        out = out.substring( basedir.getAbsolutePath().length() );
        entries.addWebClassPathEntry( project.getFullPath().append( out ).toString() );

        IMaven embedder = MavenPlugin.lookup( IMaven.class );
        ArtifactRepository localRepository = embedder.getLocalRepository();
        Collection<Artifact> artifacts = mavenProject.getRuntimeArtifacts();
        for ( Artifact artifact : artifacts )
        {
            IProject workspaceProject = getWorkspaceProject( artifact );
            if ( workspaceProject != null )
            {
                IPath path = workspaceProject.getFullPath();
                console.logMessage( "add Workspace project " + path );
                // TODO read build output from IProject ?
                if ( "test-jar".equals( artifact.getType() ) )
                {
                    entries.addWebClassPathEntry( path.append( "target/test-classes" ).toString() );
                }
                else
                {
                    entries.addWebClassPathEntry( path.append( "target/classes" ).toString() );
                }
            }
            else
            {
                console.logMessage( "add dependency " + artifact.toString() );
                entries.addWebClassPathEntry( localRepository.getBasedir() + "/" + localRepository.pathOf( artifact ) );
            }
        }
        tomcatProject.setWebClassPathEntries( entries );

        // TODO use maven-war-plugin containerConfigXML ?
        String context = mavenProject.getProperties().getProperty( "tomcat.extraInfo", TOMCAT_CONTEXT );
        File extraInfo = new File( basedir, context );
        if ( extraInfo.exists() )
        {
            try
            {
                console.logMessage( "Read Tomcat testing configuration from " + extraInfo );
                String tomcatContext = FileUtil.readTextFile( extraInfo );
                int root = tomcatContext.indexOf( "<Context" );
                int start = tomcatContext.indexOf( ">", root );
                int stop = tomcatContext.indexOf( "</Context>" );
                tomcatContext = tomcatContext.substring( start + 1, stop );
                tomcatProject.setExtraInfo( tomcatContext );
            }
            catch ( IOException e )
            {
                console.logError( "Failed to read tomcat test context " + context + " : " + e.getMessage() );
            }
        }

        try
        {
            tomcatProject.saveProperties();
            tomcatProject.updateContext();
        }
        catch ( IOException e )
        {
            console.logError( "Failed to configure Sysdeo Tomcat : " + e.getMessage() );
        }
        addProjectToSourcePathPref( project );
    }

    private IProject getWorkspaceProject( Artifact artifact )
    {
        MavenProjectManager mavenProjectManager = MavenPlugin.getDefault().getMavenProjectManager();
        artifact.isSnapshot();
        IMavenProjectFacade workspaceProject =
            mavenProjectManager
                .getMavenProject( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() );

        if ( workspaceProject != null && workspaceProject.getFullPath( artifact.getFile() ) != null )
        {
            return workspaceProject.getProject();
        }
        return null;
    }

    protected String extractMavenConfiguration( Plugin plugin, String parameter, String defaultValue )
    {
        if ( plugin != null )
        {
            Object configuration = plugin.getConfiguration();
            if ( configuration instanceof Xpp3Dom )
            {
                Xpp3Dom configDom = (Xpp3Dom) configuration;
                Xpp3Dom parameterValue = configDom.getChild( parameter );
                if ( parameterValue != null )
                {
                    return parameterValue.getValue();
                }
            }
        }
        return defaultValue;
    }

    private void addProjectToSourcePathPref( IProject project )
    {
        List projects = TomcatLauncherPlugin.getDefault().getProjectsInSourcePath();
        ProjectListElement ple = new ProjectListElement( project );
        if ( !projects.contains( ple ) )
        {
            projects.add( ple );
            TomcatLauncherPlugin.getDefault().setProjectsInSourcePath( projects );
        }
    }

}
